#include "Nano100Series.h"
#include "DispModule.h"
#include "BrgHdmiMipi.h"
#include "GpioI2c2.h"

#define TPS65132_I2C_ADDR 0x3E

#define TPS65132_REG_ADDR_VPOS 0x00
#define TPS65132_REG_ADDR_VNEG 0x01


static int TPS65132Write(uint8_t reg_addr, uint8_t reg_val)
{
	struct i2c_msg_t i2c_msg;
	int ret;
	uint8_t buf[2];

	buf[0] = reg_addr;
	buf[1] = reg_val;

	i2c_msg.addr = TPS65132_I2C_ADDR;
	i2c_msg.tx_buf = buf;
	i2c_msg.tx_to_write = 2;
	i2c_msg.tx_write = 0;
	i2c_msg.rx_buf = NULL;
	i2c_msg.rx_to_read = 0;
	i2c_msg.rx_read = 0;

	ret = GpioI2c2Xfer(&i2c_msg);
	if (ret < 0) {
		return 0;
	} else {
		return i2c_msg.tx_write;
	}
}

static int TPS65132Read(uint8_t reg_addr, uint8_t *reg_val)
{
	struct i2c_msg_t i2c_msg;
	int ret;
	uint8_t buf[1];

	buf[0] = reg_addr;

	i2c_msg.addr = TPS65132_I2C_ADDR;
	i2c_msg.tx_buf = buf;
	i2c_msg.tx_to_write = 1;
	i2c_msg.tx_write = 0;
	i2c_msg.rx_buf = reg_val;
	i2c_msg.rx_to_read = 1;
	i2c_msg.rx_read = 0;

	ret = GpioI2c2Xfer(&i2c_msg);
	if (ret < 0) {
		return 0;
	} else {
		return i2c_msg.rx_read;
	}
}

static void DispModuleReset(void)
{
	DISP_MODULE_RST_PIN = 0;
	DelayMs(10);
	DISP_MODULE_RST_PIN = 1;
	DelayMs(100);	// important
}

void DispModuleInit(void)
{
	uint8_t value = 0;
	int ret;

	DelayMs(100);
	ret = TPS65132Read(TPS65132_REG_ADDR_VPOS, &value);
	LogDebug("ret : %d, TPS65132_REG_ADDR_VPOS : 0x%02X\n", ret, value);
	ret = TPS65132Read(TPS65132_REG_ADDR_VNEG, &value);
	LogDebug("ret : %d, TPS65132_REG_ADDR_VNEG : 0x%02X\n", ret, value);

	TPS65132Write(TPS65132_REG_ADDR_VPOS, 0x11); // 5.7
	TPS65132Write(TPS65132_REG_ADDR_VNEG, 0x11); // -5.7

	TPS65132Read(TPS65132_REG_ADDR_VPOS, &value);
	LogDebug("TPS65132_REG_ADDR_VPOS : 0x%02X\n", value);
	TPS65132Read(TPS65132_REG_ADDR_VNEG, &value);
	LogDebug("TPS65132_REG_ADDR_VNEG : 0x%02X\n", value);

	DelayMs(10);
	DISP_MODULE_PWR_PIN = 1;
	DelayMs(100);
	DispModuleReset();
}

void DispModuleSetBacklightLevel(uint32_t level)
{
	static int is_on = 0;

	if (level > 100) {
		level = 100;
	}
	if (level < 7) {
		level = 7;
	}
	PWM_ConfigOutputChannel(PWM0, 1, 25 * 1000, 100 - level);
	if (is_on == 0) {
		PWM_Start(PWM0, 0x01 << 1);
		PWM_EnableOutput(PWM0, 0x01 << 1);
		is_on = 1;
	}
}

void DispModuleDisplayOn(void)
{
	//Display On
	BrgHdmiMipiI2cWrite16(0x0504, 0x8039);
	BrgHdmiMipiI2cWrite16(0x0504, 0x0001);
	BrgHdmiMipiI2cWrite16(0x0504, 0x0029);
	//Exit sleep mode (Sleep out)
	BrgHdmiMipiI2cWrite16(0x0504, 0x8039);
	BrgHdmiMipiI2cWrite16(0x0504, 0x0001);
	BrgHdmiMipiI2cWrite16(0x0504, 0x0011);

	DelayMs(100);
}

void DispModuleDisplayOff(void)
{
	//Display Off
	BrgHdmiMipiI2cWrite16(0x0504, 0x8039);
	BrgHdmiMipiI2cWrite16(0x0504, 0x0001);
	BrgHdmiMipiI2cWrite16(0x0504, 0x0028);

	DelayMs(10);

	//Exit sleep mode (Sleep out)
	BrgHdmiMipiI2cWrite16(0x0504, 0x8039);
	BrgHdmiMipiI2cWrite16(0x0504, 0x0001);
	BrgHdmiMipiI2cWrite16(0x0504, 0x0010);

	DelayMs(150);
}

void DispModuleSetVideoTiming(enum video_timing_t timing)
{
	DispModuleReset();

	if (timing == VIDEO_TIMING_1440P) {
		BrgHdmiMipiI2cWrite16(0x0504, 0x8029);
		BrgHdmiMipiI2cWrite16(0x0504, 0x0002);
		BrgHdmiMipiI2cWrite16(0x0504, 0x00B0);

		BrgHdmiMipiI2cWrite16(0x0504, 0x8029);
		BrgHdmiMipiI2cWrite16(0x0504, 0x0002);
		BrgHdmiMipiI2cWrite16(0x0504, 0x01D6);

		BrgHdmiMipiI2cWrite16(0x0504, 0x8029);
		BrgHdmiMipiI2cWrite16(0x0504, 0x0002);
		BrgHdmiMipiI2cWrite16(0x0504, 0x18B3);

		BrgHdmiMipiI2cWrite16(0x0504, 0x8039);
		BrgHdmiMipiI2cWrite16(0x0504, 0x0002);
		BrgHdmiMipiI2cWrite16(0x0504, 0xFF51);

		BrgHdmiMipiI2cWrite16(0x0504, 0x8039);
		BrgHdmiMipiI2cWrite16(0x0504, 0x0002);
		BrgHdmiMipiI2cWrite16(0x0504, 0x0C53);

		BrgHdmiMipiI2cWrite16(0x0504, 0x8039);
		BrgHdmiMipiI2cWrite16(0x0504, 0x0002);
		BrgHdmiMipiI2cWrite16(0x0504, 0x0035);

		BrgHdmiMipiI2cWrite16(0x0504, 0x8029);
		BrgHdmiMipiI2cWrite16(0x0504, 0x0002);
		BrgHdmiMipiI2cWrite16(0x0504, 0x03B0);

		DelayMs(10);
	}
}
